package com.alibaba.middleware.race.sync;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.constants.ConstantUtil;
import com.constants.Constants;
import com.sync.utils.Message;
import com.sync.utils.MessageObjectDecoder;
import com.sync.utils.MessageObjectEncoder;
import com.sync.utils.ProtostuffCodec;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

/**
 *  
 */
public class Client {

	protected final static Logger logger = LoggerFactory
			.getLogger(Client.class);

	private final static int port = Constants.SERVER_PORT;

	private static boolean success = false;
	private EventLoopGroup worker = new NioEventLoopGroup(1);
	private Bootstrap bootstrap;
	private Channel messageChannel;

	public static void main(String[] args) throws InterruptedException {
		initProperties();
		logger.info("Welcome");
		// 从args获取server端的ip
		String ip = args[0];
		Client client = new Client();
		client.init();
		while (!success) {
			logger.info("连接server .... ");
			TimeUnit.MICROSECONDS.sleep(20);
			try {
				client.connect(ip, port);
			} catch (Exception e) {
			}

		}

		while (client.messageChannel == null) {
			TimeUnit.MICROSECONDS.sleep(100);
		}
		logger.info("connect server .. ");
		Message message = new Message();
		message.setStatus(Message.connect);
		ChannelFuture channel = client.messageChannel.writeAndFlush(message);
		channel.addListener(new ChannelFutureListener() {
			public void operationComplete(ChannelFuture future)
					throws Exception {
				if (!future.isSuccess()) {
					logger.error(future.cause().toString());
				}
			}
		});
	}

	/**
	 * 初始化系统属性
	 */
	private static void initProperties() {

		System.setProperty("middleware.test.home", Constants.TESTER_HOME);
		System.setProperty("middleware.teamcode", Constants.TEAMCODE);
		System.setProperty("app.logging.level", Constants.LOG_LEVEL);

	}

	public void init() {
		bootstrap = new Bootstrap();
		bootstrap.group(worker).channel(NioSocketChannel.class)
				.option(ChannelOption.TCP_NODELAY, true)
				.option(ChannelOption.SO_KEEPALIVE, false)
				.option(ChannelOption.SO_SNDBUF, ConstantUtil.socketSndBufSize)
				.option(ChannelOption.SO_RCVBUF, ConstantUtil.socketRcvBufSize)
				.handler(new ChilderChannelHandler());
	}

	public void connect(String serverIp, int port) {

		if (bootstrap == null) {
			throw new RuntimeException(" you need open Client before connect");
		}

		try {
			ChannelFuture future = bootstrap.connect(serverIp, port).sync();

			future.addListener(new ChannelFutureListener() {
				public void operationComplete(ChannelFuture future)
						throws Exception {
					Channel channel = future.channel();
					messageChannel = channel;
				}
			});
			success = true;
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void close() {
		try {
			if (messageChannel != null) {
				messageChannel.close().sync();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			worker.shutdownGracefully();
		}

	}

	private class ChilderChannelHandler
			extends
				ChannelInitializer<SocketChannel> {

		@Override
		protected void initChannel(SocketChannel channel) throws Exception {
			ChannelPipeline pip = channel.pipeline();
			pip.addLast(
					new MessageObjectEncoder(ProtostuffCodec.OneInstance()));
			pip.addLast(
					new MessageObjectDecoder(ProtostuffCodec.OneInstance()));
			pip.addLast("timeout", new IdleStateHandler(0, 0, 120));
			pip.addLast(new NettyClientHandler());
		}
	}

}
